import Vue from 'vue'
import Vuex from 'vuex'

import { INCREMENT } from '../store/mutations-types'

// 1. 安装插件 >>> 底层会执行插件的install方法
Vue.use(Vuex);

// 2. 创建一个Vuex实例对象 >>> Vuex.Store
// 这个moduleA会被放到最外层的state里面
const moduleA = {
  state: {
    name: 'Mr.zhang'
  },
  mutations: {
    updateName(state) {
      state.name = 'Mr.小三';
    }
  },
  getters: {
    fullName1: state => state.name + ' aha',
    fullName2: (state, getters, rootState) => getters.fullName1 + ' bhb ' + rootState.counter,
  },
  actions: {
    // 这里的context不在是$store对象了, 
    // context里面包含的属性
    // state: 当前模块的state数据
    // commit: 当前模块提交, 只会提交到当前模块的mutations方法里
    // dispatch: 当前模块异步消息分发
    // getters: 当前模块getters属性获取
    // rootGetters: 根组织getters属性获取
    // rootState: 根阻止state数据获取
    // aUpdateName(context) {
    // 使用对象解构取值: 对象中有的属性, 可以直接通过 {} 获取
    aUpdateName({ commit, state, rootState }) {
      // console.log(context);
      setTimeout(() => {
        commit('updateName');
      }, 1000);
    }
  },
}

const store = new Vuex.Store({
  // 保存状态
  state: {
    // 这些属性都会被加入到响应式系统中, 而响应式系统会监听属性是否变化, 当属性发生变化时, 会通知所有界面中用到该属性的地方, 进行刷新
    counter: 1000,
    students: [
      { id: 1, name: 'Mr.chen', age: 16 },
      { id: 2, name: 'Mr.xiao', age: 28 },
      { id: 3, name: 'Mr.wang', age: 20 },
      { id: 4, name: 'Mr.cao', age: 26 }
    ],
    info: {
      name: 'kobe',
      age: 50,
      height: 1.98
    }
  },

  // 修改同步提交方法 [commit]
  mutations: {
    // 增加
    [INCREMENT](state, n) {
      if (n) { state.counter += n; }
      else { state.counter++; }
    },

    // 减少
    decrement(state) {
      state.counter--;
    },

    // addStudent(state, student) {
    // 第二种提交风格获取
    addStudent(state, payload) {
      // payload: 负载, 整一个对象, 包括type等...
      let f = state.students.some(s => s.id == payload.stu.id);
      if (!f) {
        state.students.push(payload.stu);
      } else {
        alert("此学生已经添加过了哦~");
      }
    },

    updateInfo(state, name) {
      state.info.name = name;
      // 老版本做不到响应式 >>> 
      // 往info对象中添加address属性
      // state.info['address'] = '洛杉矶';

      // 无论是否新老版本都可以做到 >>> 
      // 使用Vue.set()使之变成响应式的
      // Vue.set(state.info, 'address', '洛杉矶');

      // 老版本做不到响应式 >>> 
      // 删除对象中的属性
      // delete state.info.name

      // 无论是否新老版本都可以做到 >>>
      // 使用Vue, delete ()
      // Vue.delete(state.info, 'name');

      // 注!!! 如果是使用了异步操作呢？
      // setTimeout(() => {
      //   state.info.name = name;
      // }, 1000);
      // ps: 我们可以看到界面改变了, 但是Vuex状态管理中对象的值却没有改变, 这是因为Vuex并没有记录[跟踪]到改变, 所以Vuex官方文档中说明最好不要在mutation中使用异步操作, 那么如果真的需要用到异步操作的时候怎么办呢？Vuex给我提供了actions: {}
    }
  },

  // 异步操作事件提交
  actions: {
    // context: 上下文, 可以看成$store
    aUpdateInfo(context, payload) {
      // 2. 优雅的Promise
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          // 不要试图跳过mutation, 最终还是要通过
          // vue-component >>> Actions >>> Mutations >>> state >>> vue-component
          context.commit('updateInfo', payload);

          // 1. 完成后调用回调方法 告诉外面已经完成了 [不够优雅]
          // payload.success();

          // Promise的成功返回
          resolve('内部已经完成操作');
        }, 1000)
      })
    }
  },

  // 类似Vue组件中的computed[计算属性]
  getters: {
    powerCounter(state) {
      return state.counter * state.counter;
    },

    // 大于20的学生
    more20stu(state) {
      return state.students.filter(s => s.age > 20);
    },

    // 大于20的学生的个数
    // 第一个参数为当前state
    // 第二个参数为当前getters, 可以从中获取已经写过的方法返回值
    more20stuLength(state, getters) {
      return getters.more20stu.length;
    },

    // 根据用于传入的年龄, 然后动态获取满足条件的人
    // 因为当前使用的形式是以属性形式直接调用的, 我们在内部返回一个函数, 通过该函数的形参来接收外部传递的参数
    moreAgeStu(state) {
      // return function (age) {
      //   return state.students.filter(s => s.age > age);
      // }
      return age => state.students.filter(s => s.age > age);
    }
  },

  // 模块划分: 内部可以定义多个对象, 对象内又可以定义state、mutations、actions、getters... [套娃]
  modules: {
    moduleA,

    moduleB: {
      // ...
    }
  }
})

// 3. 导出当前Vuex实例对象

export default store
